package main

import (
	"fmt"
	"log"
	"os"
	"path/filepath"
	"strings"
	"sync"
	"time"

	"ofd/pkg/ofdinv"

	"github.com/xuri/excelize/v2"
)

func main() {
	GetOFDInvInfo()
	fmt.Println("Press any key to exit...")
	b := make([]byte, 1)
	os.Stdin.Read(b)
}

func GetOFDInvInfo() {
	dir, err := os.Getwd()
	if err != nil {
		log.Fatal("获取当前目录失败:", err)
	}
	files, err := scanOFDFiles(dir)
	if err != nil {
		log.Fatal("扫描文件失败:", err)
	}
	if len(files) == 0 {
		fmt.Println("当前目录未发现OFD发票文件")
		return
	}

	fmt.Printf("发现 %d 个OFD发票文件，开始并发解析...\n", len(files))

	f := excelize.NewFile()

	// 创建发票数据sheet页
	invoiceSheet := "发票数据"
	f.NewSheet(invoiceSheet)
	f.DeleteSheet("Sheet1")

	// 创建货物运输服务sheet页
	transportSheet := "货物运输服务"
	f.NewSheet(transportSheet)

	// 设置发票数据表头
	headers := []string{"文件名", "发票类型", "发票号码", "开票日期", "项目名称", "规格型号", "单位", "数量", "单价", "金额", "税率", "税额", "购方名称", "购方税号", "销方名称", "销方税号", "开票人", "特定业务类型", "备注"}
	for col, h := range headers {
		cell, _ := excelize.CoordinatesToCellName(col+1, 1)
		f.SetCellValue(invoiceSheet, cell, h)
	}

	// 设置货物运输服务表头
	transportHeaders := []string{"文件名", "发票号码", "开票日期", "运输工具种类", "运输工具牌号", "起运地", "到达地", "运输货物名称", "购方名称", "购方税号", "销方名称", "销方税号"}
	for col, h := range transportHeaders {
		cell, _ := excelize.CoordinatesToCellName(col+1, 1)
		f.SetCellValue(transportSheet, cell, h)
	}

	// 使用通道和WaitGroup实现并发处理
	var wg sync.WaitGroup
	results := make(chan *InvoiceResult, len(files))

	// 并发处理每个文件
	for _, file := range files {
		wg.Add(1)
		go func(filePath string) {
			defer wg.Done()
			processInvoice(filePath, results)
		}(file)
	}

	// 等待所有goroutine完成并关闭通道
	go func() {
		wg.Wait()
		close(results)
	}()

	// 收集结果并写入Excel
	invoiceRowIndex := 2
	transportRowIndex := 2
	successCount := 0
	failCount := 0

	for result := range results {
		if result.Err != nil {
			log.Printf("文件 %s 处理失败: %v\n", result.FileName, result.Err)
			failCount++
			continue
		}

		// 为每个商品创建一行
		if len(result.InvoiceInfo.Items) > 0 {
			for _, item := range result.InvoiceInfo.Items {
				writeInvoiceRow(f, invoiceSheet, invoiceRowIndex, result.FileName, result.InvTypeStr, result.BusinessType, result.InvoiceInfo, &item)
				invoiceRowIndex++
			}
		} else {
			// 如果没有商品，至少写一行基础信息
			writeInvoiceRow(f, invoiceSheet, invoiceRowIndex, result.FileName, result.InvTypeStr, result.BusinessType, result.InvoiceInfo, nil)
			invoiceRowIndex++
		}

		// 为每个运输明细创建一行
		if len(result.InvoiceInfo.TransportDetails) > 0 {
			for _, transportDetail := range result.InvoiceInfo.TransportDetails {
				writeTransportRow(f, transportSheet, transportRowIndex, result.FileName, result.InvoiceInfo, &transportDetail)
				transportRowIndex++
			}
		}

		successCount++
	}

	// 设置sheet样式
	setSheetStyle(f, invoiceSheet, headers, invoiceRowIndex)
	setSheetStyle(f, transportSheet, transportHeaders, transportRowIndex)

	// 保存文件
	output := "invReport" + time.Now().Format("20060102150304") + ".xlsx"
	if err := f.SaveAs(output); err != nil {
		log.Fatal("保存Excel失败:", err)
	}

	fmt.Printf("处理完成！成功: %d, 失败: %d\n", successCount, failCount)
	fmt.Printf("结果已保存到: %s\n", output)
}

// InvoiceResult 发票处理结果
type InvoiceResult struct {
	FileName     string
	InvoiceInfo  *ofdinv.InvoiceInfo
	InvTypeStr   string // 发票类型字符串
	BusinessType string // 业务类型
	Err          error
}

// processInvoice 处理单个发票文件
func processInvoice(filePath string, results chan<- *InvoiceResult) {
	// 创建OFD阅读器
	reader, err := ofdinv.NewOFDReader(filePath)
	if err != nil {
		results <- &InvoiceResult{
			FileName: filepath.Base(filePath),
			Err:      fmt.Errorf("创建OFD阅读器失败: %v", err),
		}
		return
	}
	defer reader.Close()

	invTypeStr, businessType, err := reader.GetINVType()
	if err != nil {
		results <- &InvoiceResult{
			FileName: filepath.Base(filePath),
			Err:      err,
		}
		return
	}
	//fmt.Printf("检测到发票类型: %s, 业务类型: %s\n", invTypeStr, businessType)

	// 根据业务类型选择解析器
	var info *ofdinv.InvoiceInfo
	switch businessType {
	case "普通业务", "成品油":
		parser := ofdinv.NewVATParser(reader)
		info, err = parser.Parse()
	case "货物运输服务":
		parser := ofdinv.NewTransportParser(reader)
		info, err = parser.Parse()
	default:
		err = fmt.Errorf("不支持的发票业务类型: %s", businessType)
	}

	if err != nil {
		results <- &InvoiceResult{
			FileName: filepath.Base(filePath),
			Err:      fmt.Errorf("解析发票失败: %v", err),
		}
		return
	}

	results <- &InvoiceResult{
		FileName:     filepath.Base(filePath),
		InvoiceInfo:  info,
		InvTypeStr:   invTypeStr,
		BusinessType: businessType,
	}
}

// writeInvoiceRow 将发票信息写入Excel的一行
func writeInvoiceRow(f *excelize.File, sheet string, row int, fileName string, invTypeStr string, businessType string, invoiceInfo *ofdinv.InvoiceInfo, item *ofdinv.VATItem) {
	// 文件名
	cell1, _ := excelize.CoordinatesToCellName(1, row)
	f.SetCellValue(sheet, cell1, fileName)

	// 发票类型
	cell2, _ := excelize.CoordinatesToCellName(2, row)
	f.SetCellValue(sheet, cell2, invTypeStr)

	// 发票号码
	cell3, _ := excelize.CoordinatesToCellName(3, row)
	f.SetCellValue(sheet, cell3, invoiceInfo.InvoiceNumber)

	// 开票日期
	cell4, _ := excelize.CoordinatesToCellName(4, row)
	f.SetCellValue(sheet, cell4, invoiceInfo.InvoiceDate)

	// 项目名称
	var itemName string
	if item != nil {
		itemName = item.Name
	}
	cell5, _ := excelize.CoordinatesToCellName(5, row)
	f.SetCellValue(sheet, cell5, itemName)

	// 规格型号
	var spec string
	if item != nil {
		spec = item.Spec
	}
	cell6, _ := excelize.CoordinatesToCellName(6, row)
	f.SetCellValue(sheet, cell6, spec)

	// 单位
	var unit string
	if item != nil {
		unit = item.Unit
	}
	cell7, _ := excelize.CoordinatesToCellName(7, row)
	f.SetCellValue(sheet, cell7, unit)

	// 数量
	var quantity float64
	if item != nil {
		quantity = item.Quantity
	}
	cell8, _ := excelize.CoordinatesToCellName(8, row)
	f.SetCellValue(sheet, cell8, quantity)

	// 单价
	var unitPrice float64
	if item != nil {
		unitPrice = item.UnitPrice
	}
	cell9, _ := excelize.CoordinatesToCellName(9, row)
	f.SetCellValue(sheet, cell9, unitPrice)

	// 金额
	var amount float64
	if item != nil {
		amount = item.Amount
	}
	cell10, _ := excelize.CoordinatesToCellName(10, row)
	f.SetCellValue(sheet, cell10, amount)

	// 税率
	var taxRate string
	if item != nil {
		taxRate = item.TaxRate
	}
	cell11, _ := excelize.CoordinatesToCellName(11, row)
	f.SetCellValue(sheet, cell11, taxRate)

	// 税额
	var taxAmount float64
	if item != nil {
		taxAmount = item.TaxAmount
	}
	cell12, _ := excelize.CoordinatesToCellName(12, row)
	f.SetCellValue(sheet, cell12, taxAmount)

	// 购方名称
	cell13, _ := excelize.CoordinatesToCellName(13, row)
	f.SetCellValue(sheet, cell13, invoiceInfo.BuyerName)

	// 购方税号
	cell14, _ := excelize.CoordinatesToCellName(14, row)
	f.SetCellValue(sheet, cell14, invoiceInfo.BuyerTaxID)

	// 销方名称
	cell15, _ := excelize.CoordinatesToCellName(15, row)
	f.SetCellValue(sheet, cell15, invoiceInfo.SellerName)

	// 销方税号
	cell16, _ := excelize.CoordinatesToCellName(16, row)
	f.SetCellValue(sheet, cell16, invoiceInfo.SellerTaxID)

	// 开票人
	cell17, _ := excelize.CoordinatesToCellName(17, row)
	f.SetCellValue(sheet, cell17, invoiceInfo.Drawer)

	// 特定业务类型
	cell18, _ := excelize.CoordinatesToCellName(18, row)
	f.SetCellValue(sheet, cell18, businessType)

	// 备注
	cell19, _ := excelize.CoordinatesToCellName(19, row)
	f.SetCellValue(sheet, cell19, invoiceInfo.Note)
}

// setSheetStyle 设置sheet样式
func setSheetStyle(f *excelize.File, sheet string, headers []string, rowIndex int) {
	// 设置冻结首行 - 冻结第一行
	if err := f.SetPanes(sheet, &excelize.Panes{
		Freeze: true,
		XSplit: 0,
		YSplit: 1, // 冻结第一行
	}); err != nil {
		log.Printf("设置冻结首行失败: %v", err)
	}

	// 设置自动筛选 - 为表头行添加筛选器
	if err := f.AutoFilter(sheet, "A1:R1", nil); err != nil {
		log.Printf("设置自动筛选失败: %v", err)
	}

	// 设置自适应列宽
	for col := 1; col <= len(headers); col++ {
		maxWidth := 8.0 // 最小宽度
		for row := 1; row < rowIndex; row++ {
			cell, _ := excelize.CoordinatesToCellName(col, row)
			value, err := f.GetCellValue(sheet, cell)
			if err != nil {
				continue
			}
			// 根据内容长度计算宽度，考虑中文字符
			width := float64(len([]rune(value))) * 1.2
			if width > maxWidth {
				maxWidth = width
			}
		}
		// 根据列类型设置不同的宽度限制
		switch col {
		case 3, 5, 13, 14, 15, 16: // 项目名称、购方名称、销方名称 - 较宽
			if maxWidth < 20 {
				maxWidth = 20
			}
			if maxWidth > 60 {
				maxWidth = 60
			}
		case 4, 6, 7, 8, 9, 10, 11, 12, 17: // 其他列 - 中等宽度
			if maxWidth < 15 {
				maxWidth = 15
			}
			if maxWidth > 30 {
				maxWidth = 30
			}
		case 1, 2: // 发票类型 - 固定宽度
			maxWidth = 15
		default:
			maxWidth = 20
		}
		colName, _ := excelize.ColumnNumberToName(col)
		f.SetColWidth(sheet, colName, colName, maxWidth)
	}

	// 设置字体样式 - 宋体10号字
	style, err := f.NewStyle(&excelize.Style{
		Font: &excelize.Font{
			Family: "宋体",
			Size:   10,
		},
	})
	if err != nil {
		log.Printf("创建字体样式失败: %v", err)
	} else {
		// 应用到整个工作表
		endCell, _ := excelize.CoordinatesToCellName(len(headers), rowIndex-1)
		f.SetCellStyle(sheet, "A1", endCell, style)
	}
}

// writeTransportRow 将运输信息写入Excel的一行
func writeTransportRow(f *excelize.File, sheet string, row int, fileName string, invoiceInfo *ofdinv.InvoiceInfo, transportDetail *ofdinv.TransportDetails) {
	// 文件名
	cell1, _ := excelize.CoordinatesToCellName(1, row)
	f.SetCellValue(sheet, cell1, fileName)

	// 发票号码
	cell2, _ := excelize.CoordinatesToCellName(2, row)
	f.SetCellValue(sheet, cell2, invoiceInfo.InvoiceNumber)

	// 开票日期
	cell3, _ := excelize.CoordinatesToCellName(3, row)
	f.SetCellValue(sheet, cell3, invoiceInfo.InvoiceDate)

	// 运输工具种类
	cell4, _ := excelize.CoordinatesToCellName(4, row)
	f.SetCellValue(sheet, cell4, transportDetail.VehicleType)

	// 运输工具牌号
	cell5, _ := excelize.CoordinatesToCellName(5, row)
	f.SetCellValue(sheet, cell5, transportDetail.VehicleNumber)

	// 起运地
	cell6, _ := excelize.CoordinatesToCellName(6, row)
	f.SetCellValue(sheet, cell6, transportDetail.Departure)

	// 到达地
	cell7, _ := excelize.CoordinatesToCellName(7, row)
	f.SetCellValue(sheet, cell7, transportDetail.Destination)

	// 运输货物名称
	cell8, _ := excelize.CoordinatesToCellName(8, row)
	f.SetCellValue(sheet, cell8, transportDetail.CargoName)

	// 购方名称
	cell9, _ := excelize.CoordinatesToCellName(9, row)
	f.SetCellValue(sheet, cell9, invoiceInfo.BuyerName)

	// 购方税号
	cell10, _ := excelize.CoordinatesToCellName(10, row)
	f.SetCellValue(sheet, cell10, invoiceInfo.BuyerTaxID)

	// 销方名称
	cell11, _ := excelize.CoordinatesToCellName(11, row)
	f.SetCellValue(sheet, cell11, invoiceInfo.SellerName)

	// 销方税号
	cell12, _ := excelize.CoordinatesToCellName(12, row)
	f.SetCellValue(sheet, cell12, invoiceInfo.SellerTaxID)
}

func scanOFDFiles(dir string) ([]string, error) {
	var files []string
	err := filepath.Walk(dir, func(path string, info os.FileInfo, err error) error {
		if err != nil {
			return err
		}
		if !info.IsDir() && strings.EqualFold(filepath.Ext(path), ".ofd") {
			files = append(files, path)
		}
		return nil
	})
	return files, err
}
